/*
 * @Description: 缓存数据
 * @Author: DHL
 * @Date: 2022-01-15 09:05:04
 * @LastEditors: DHL
 * @LastEditTime: 2022-11-05 14:22:25
 */

import { defineStore } from 'pinia'
import { store } from '/@/store'
import BpmnModeler from 'bpmn-js/lib/Modeler'
import { arrayRemoveItem } from '/@/utils/twUtils'
import { buildLengthUUID } from '/@/utils/uuid'

export interface IBpmnState {
  /**
   * 前缀
   */
  prefix: string

  /**
   * bpmnModeler
   */
  bpmnModeler: any

  /**
   * modeling
   */
  modeling: any

  /**
   * moddle
   */
  moddle: any

  /**
   * eventBus
   */
  eventBus: any

  /**
   * bpmnFactory
   */
  bpmnFactory: any

  /**
   * elementFactory
   */
  elementFactory: any

  /**
   * elementRegistry
   */
  elementRegistry: any

  /**
   * replace
   */
  replace: any

  /**
   * selection
   */
  selection: any

  /**
   * 当前选中的元素
   */
  activatedElement: any

  /**
   * 当前选中的元素主键
   */
  activatedElementId: string

  /**
   * 当前选中的元素类型
   */
  activatedElementType: string
}

const bpmnStore = defineStore({
  id: 'bpmnStore',
  state: (): IBpmnState => ({
    prefix: 'flowable',
    bpmnModeler: null,
    modeling: null,
    moddle: null,
    eventBus: null,
    bpmnFactory: null,
    elementFactory: null,
    elementRegistry: null,
    replace: null,
    selection: null,
    activatedElement: null,
    activatedElementId: '',
    activatedElementType: ''
  }),
  getters: {
    //////////////////////////////////////////////////
    // 元素注册表
    //////////////////////////////////////////////////

    /**
     * 获取elementRegistry中的元素
     * @param state
     * @returns
     */
    getByElementRegistry(state) {
      return (type: string) => {
        return state.elementRegistry.find((el: { type: string }) => el.type === type)
      }
    },

    //////////////////////////////////////////////////
    // 选中元素
    //////////////////////////////////////////////////

    /**
     * 获取选中元素的业务对象
     */
    getActivatedElementBusinessObject(state) {
      return (key: string) => {
        let businessObject = {}
        if (state.activatedElement) {
          businessObject = state.activatedElement.businessObject
        }

        return businessObject[key]
      }
    },

    //////////////////////////////////////////////////
    // 用户任务审批规则
    //////////////////////////////////////////////////
    /**
     * 获取用户任务审批规则
     * @param state
     * @returns
     */
    getApprovalRules(state) {
      const variables =
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type === `${state.prefix}:ApprovalRules`
        )[0] ?? {}

      let rtn = {}

      if (variables && variables.body) {
        rtn = JSON.parse(variables.body)
      }

      return rtn
    },

    //////////////////////////////////////////////////
    // 流程变量
    //////////////////////////////////////////////////

    /**
     * 获取流程变量
     * @param state
     * @returns
     */
    getVariables(state) {
      const variables =
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type === `${state.prefix}:Variables`
        )[0] ?? {}

      let rtn = {}

      if (variables && variables.body) {
        rtn = JSON.parse(variables.body)
      }

      return rtn
    },

    //////////////////////////////////////////////////
    // 监听器
    //////////////////////////////////////////////////

    /**
     * 获取执行监听器集合
     */
    getExecutionListener(state) {
      return () =>
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type === `${state.prefix}:ExecutionListener`
        ) ?? []
    },

    /**
     * 获取其他执行监听器集合
     * @param state
     * @returns
     */
    getOtherExecutionListener(state) {
      return () =>
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type !== `${state.prefix}:ExecutionListener`
        ) ?? []
    },

    //////////////////////////////////////////////////
    // 属性
    //////////////////////////////////////////////////
    /**
     * 获取属性
     * @param state
     * @returns
     */
    getProperties(state) {
      return () =>
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type === `${state.prefix}:Properties`
        ) ?? []
    },

    /**
     * 获取其他属性
     * @param state
     * @returns
     */
    getOtherProperties(state) {
      return () =>
        state.activatedElement?.businessObject?.extensionElements?.values?.filter(
          (ex: { $type: string }) => ex.$type !== `${state.prefix}:Properties`
        ) ?? []
    }
  },
  actions: {
    /**
     * 构建BpmnModeler
     * @returns
     */
    buildBpmnModeler(options: any) {
      if (!this.bpmnModeler) {
        this.bpmnModeler = markRaw(new BpmnModeler(options))

        this.modeling = markRaw(this.bpmnModeler.get('modeling'))
        this.moddle = markRaw(this.bpmnModeler.get('moddle'))
        this.eventBus = markRaw(this.bpmnModeler.get('eventBus'))
        this.bpmnFactory = markRaw(this.bpmnModeler.get('bpmnFactory'))
        this.elementFactory = markRaw(this.bpmnModeler.get('elementFactory'))
        this.elementRegistry = markRaw(this.bpmnModeler.get('elementRegistry'))
        this.replace = markRaw(this.bpmnModeler.get('replace'))
        this.selection = markRaw(this.bpmnModeler.get('selection'))
      }
    },

    /**
     * 销毁BpmnModeler
     */
    destroy() {
      if (this.bpmnModeler) {
        this.bpmnModeler.destroy()
      }

      this.bpmnModeler = null
      this.modeling = null
      this.moddle = null
      this.eventBus = null
      this.bpmnFactory = null
      this.elementFactory = null
      this.elementRegistry = null
      this.replace = null
      this.selection = null
      this.activatedElement = null
      this.activatedElementId = ''
      this.activatedElementType = ''
    },

    /**
     * 设置选中的元素
     * @param activatedElement
     */
    setActivatedElement(activatedElement: any) {
      if (activatedElement) {
        this.activatedElementId = activatedElement.id
        this.activatedElementType = activatedElement.type.split(':')[1] || ''
        this.activatedElement = markRaw(activatedElement)
      }
    },

    /**
     * modeling
     * 更新属性
     */
    updateProperties(attrObj: any) {
      this.modeling.updateProperties(this.activatedElement, attrObj)
    },

    /**
     * 根据ID删除根节点
     * @param type
     * @param id
     */
    removeRootElementsById(type: string, id: string) {
      let rootElements = this.bpmnModeler.getDefinitions().rootElements
      rootElements.forEach((el: any) => {
        if (el.$type === type && el.id === id) {
          arrayRemoveItem(rootElements, el)
        }
      })
    },

    /**
     * 更新元素扩展属性
     * @param extensionList
     */
    updateElementExtensions(extensionList: any) {
      const extensions = this.moddle.create('bpmn:ExtensionElements', {
        values: extensionList
      })

      this.updateProperties({
        extensionElements: extensions
      })
    },

    /**
     * 更新属性
     * @param oldVal  原值
     * @param newVal  新值
     */
    updateModdleProperties(oldVal: any, newVal: any) {
      this.modeling.updateModdleProperties(this.activatedElement, oldVal, newVal)
    },

    /**
     * 创建元素
     * @param elementName 元素名称
     * @param properties 元素属性
     */
    createModdleElement(elementName: string, properties?: any) {
      if (properties) {
        return this.moddle.create(elementName, properties)
      } else {
        return this.moddle.create(elementName)
      }
    },

    //////////////////////////////////////////////////
    // 用户任务审批规则
    //////////////////////////////////////////////////
    /**
     * 添加流程审批规则
     * @param approvalRules 审批规则
     */
    setApprovalRules(approvalRules: object) {
      let body: Nullable<string> = null
      if (approvalRules) {
        body = JSON.stringify(approvalRules)
      }

      const approvalRulesElement = this.createModdleElement(`${this.prefix}:ApprovalRules`, {
        body: body
      })

      this.updateElementExtensions([approvalRulesElement])
    },

    //////////////////////////////////////////////////
    // 流程变量
    //////////////////////////////////////////////////
    /**
     * 添加流程变量
     * @param variables 对象
     */
    variablesAdd(variables: object) {
      const origVal = this.getVariables

      for (const key in variables) {
        origVal[key] = variables[key]
      }

      const variablesList = this.createModdleElement(`${this.prefix}:Variables`, {
        body: JSON.stringify(origVal)
      })

      this.updateElementExtensions([variablesList])
    },

    /**
     * 删除流程变量
     * @param key
     */
    variablesDelete(key: string) {
      const origVal = this.getVariables

      delete origVal[key]

      let body: Nullable<string> = null

      if (Object.keys(origVal).length > 0) {
        body = JSON.stringify(origVal)
      }

      const variablesList = this.createModdleElement(`${this.prefix}:Variables`, {
        body: body
      })

      this.updateElementExtensions([variablesList])
    },

    //////////////////////////////////////////////////
    // 监听器
    //////////////////////////////////////////////////

    /**
     * 创建监听器对象
     * @param options
     * @param isTask
     */
    createListenerObject(options: any, isTask = false) {
      const listenerObj = Object.create(null)
      listenerObj.event = options.event

      // 任务监听器特有的 id 字段
      if (isTask) {
        listenerObj.id = options.id
      }

      switch (options.listenerType) {
        case 'scriptListener':
          listenerObj.script = this.createScriptObject(options)
          break
        case 'expressionListener':
          listenerObj.expression = options.expression
          break
        case 'delegateExpressionListener':
          listenerObj.delegateExpression = options.delegateExpression
          break
        default:
          listenerObj.class = options.class
      }

      // 注入字段
      if (options.fields) {
        listenerObj.fields = options.fields.map((field: any) => {
          return this.createFieldObject(field)
        })
      }

      // 任务监听器的 定时器 设置
      if (isTask && options.event === 'timeout' && !!options.eventDefinitionType) {
        const timeDefinition = this.moddle.create('bpmn:FormalExpression', {
          body: options.eventTimeDefinitions
        })

        const TimerEventDefinition = this.moddle.create('bpmn:TimerEventDefinition', {
          id: `TimerEventDefinition_${buildLengthUUID()}`,
          [`time${options.eventDefinitionType.replace(/^\S/, (s: string) => s.toUpperCase())}`]:
            timeDefinition
        })
        listenerObj.eventDefinitions = [TimerEventDefinition]
      }

      return this.moddle.create(
        `${this.prefix}:${isTask ? 'TaskListener' : 'ExecutionListener'}`,
        listenerObj
      )
    },

    /**
     * 创建脚本对象
     * @param options
     * @returns
     */
    createScriptObject(options: any) {
      const { scriptType, scriptFormat, value, resource } = options
      const scriptConfig =
        scriptType === 'inlineScript' ? { scriptFormat, value } : { scriptFormat, resource }
      return this.moddle.create(`${this.prefix}:Script`, scriptConfig)
    },

    /**
     * 创建 监听器的注入字段 对象
     * @param option
     * @returns
     */
    createFieldObject(option: any) {
      const { name, fieldType, string, expression } = option
      const fieldConfig = fieldType === 'string' ? { name, string } : { name, expression }
      return this.moddle.create(`${this.prefix}:Field`, fieldConfig)
    }
  }
})

export function useBpmnStore() {
  return bpmnStore(store)
}
